package top.cardone.security.impl;

import lombok.Setter;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
import org.apache.commons.crypto.cipher.CryptoCipher;
import org.apache.commons.crypto.cipher.CryptoCipherFactory;
import org.apache.commons.crypto.utils.Utils;
import top.cardone.core.CodeException;
import top.cardone.security.Descipher;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Properties;

/**
 * Created by yht on 16-2-2.
 */
public class DescipherImpl implements Descipher {
	@Setter
	private String keyAlgorithm = "AES";

	@Setter
	private String cipherAlgorithm = "AES/CBC/PKCS5Padding";

	@Setter
	private String key = "cardone.";

	@Override
	public String encrypt(String salt, String text) {
		try {
			Properties properties = new Properties();

			properties.setProperty(CryptoCipherFactory.CLASSES_KEY, CryptoCipherFactory.CipherProvider.JCE.getClassName());

			try (CryptoCipher cryptoCipher = Utils.getCipherInstance(cipherAlgorithm, properties)) {
				SecretKeySpec secretKeySpec = new SecretKeySpec(org.apache.commons.codec.digest.DigestUtils.md5(this.key + salt), keyAlgorithm);
				IvParameterSpec ivParameterSpec = new IvParameterSpec(org.apache.commons.codec.digest.DigestUtils.md5(this.key + salt));

				cryptoCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);

				byte[] input = StringUtils.getBytesUtf8(text);

				byte[] output = new byte[32];

				int updateBytes = cryptoCipher.update(input, 0, input.length, output, 0);

				int finalBytes = cryptoCipher.doFinal(input, 0, 0, output, updateBytes);

				return Base64.encodeBase64String(Arrays.copyOf(output, updateBytes + finalBytes));
			}
		} catch (Exception e) {
			throw new CodeException("000000", e);
		}
	}

	@Override
	public String decrypt(String salt, String text) {
		try {
			Properties properties = new Properties();

			properties.setProperty(CryptoCipherFactory.CLASSES_KEY, CryptoCipherFactory.CipherProvider.JCE.getClassName());

			try (CryptoCipher cryptoCipher = Utils.getCipherInstance(cipherAlgorithm, properties)) {
				SecretKeySpec secretKeySpec = new SecretKeySpec(org.apache.commons.codec.digest.DigestUtils.md5(this.key + salt), keyAlgorithm);
				IvParameterSpec ivParameterSpec = new IvParameterSpec(org.apache.commons.codec.digest.DigestUtils.md5(this.key + salt));

				cryptoCipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);

				byte[] input = Base64.decodeBase64(text);

				byte[] decoded = new byte[32];

				cryptoCipher.doFinal(input, 0, input.length, decoded, 0);

				return org.apache.commons.lang3.StringUtils.trim(new String(decoded, StandardCharsets.UTF_8));
			}
		} catch (Exception e) {
			throw new CodeException("000000", e);
		}
	}
}